//
//  GCDController.m
//  GCD
//
//  Created by 宜必鑫科技 on 2017/11/6.
//  Copyright © 2017年 宜必鑫科技. All rights reserved.
//

#import "GCDController.h"
#import <Masonry.h>
#import <ReactiveObjC.h>
@interface GCDController ()
@property (nonatomic, strong) UIImageView *imageView;
@end

@implementation GCDController



/**
 iOS GCD中级篇 - dispatch_semaphore
 */
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view setBackgroundColor:[UIColor whiteColor]];
    
    _imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 20, 100, 100)];
    [self.view addSubview:_imageView];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.backgroundColor = [UIColor redColor];
    [button setTitle:@"异步并行执行" forState:0];
    [self.view addSubview:button];
    [button mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        make.top.mas_equalTo(100);
        make.height.mas_equalTo(50);
    }];
    [[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        [self asyncConsurrent];
    }];
    
    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
    button1.backgroundColor = [UIColor redColor];
    [button1 setTitle:@"异步加载图片" forState:0];
    [self.view addSubview:button1];
    [button1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        make.top.equalTo(button.mas_bottom).offset(10);
        make.height.mas_equalTo(50);
    }];
    [[button1 rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        [self downImage];
    }];
    
    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];
    button2.backgroundColor = [UIColor redColor];
    [button2 setTitle:@"栅栏函数" forState:0];
    [self.view addSubview:button2];
    [button2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        make.top.equalTo(button1.mas_bottom).offset(10);
        make.height.mas_equalTo(50);
    }];
    [[button2 rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        [self barrier];
    }];
    
    UIButton *button3 = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.view addSubview:button3];
    button3.backgroundColor = [UIColor darkGrayColor];
    [button3 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        make.top.equalTo(button2.mas_bottom).offset(10);
        make.height.mas_equalTo(50);
    }];
    [button3 setTitle:@"group" forState:0];
    [[button3 rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        [self group];
    }];
    
    UIButton *button4 = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.view addSubview:button4];
    button4.backgroundColor = [UIColor darkGrayColor];
    [button4 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        make.top.equalTo(button3.mas_bottom).offset(10);
        make.height.mas_equalTo(50);
    }];
    [button4 setTitle:@"（信号量）的理解及使用" forState:0];
    [[button4 rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        [self semaphore];
    }];
    
    
    
    
    
    
    /**
     GCD 将任务添加到队列中 GCD会自动将队列中的任务取，放到对应的线程中执行
     并发队列 ：多个任务同时执行
     串行队列：任务一个一个执行
     GCD将这些存在于队列的任务取出来放到相应的线程上去执行，而队列的性质决定了在其中的任务在哪种线程上执行。
     */
    
#pragma mark - 主队列 主队列是GCD自带的一种特殊的串行队列，放在主队列中的任务，都会放到主线程中执行 任务串行执行

#pragma mark - 串行队列 同步函数不会开线程
    // 创建串行队列（队列类型传递NULL或者DISPATCH_QUEUE_SERIAL）
    dispatch_queue_t queue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
    // 2.同步 在主线程里面
    dispatch_sync(queue, ^{
         NSLog(@"同步  串行队列-----%@",[NSThread currentThread]);
    });
    // 3.异步
    dispatch_async(queue, ^{
        NSLog(@"异步  串行队列------%@",[NSThread currentThread]);
    });
    //2.同步函数 + 主队列 直接崩溃 在主线程里面 + 同步函数 + 主队列
//    dispatch_sync(dispatch_get_main_queue(), ^{
//        NSLog(@"---download1---%@",[NSThread currentThread]);
//    });


#pragma mark - 并行队列  + 异步函数 开启子线程并行执行
    //创建并发队列
    dispatch_queue_t queue1 = dispatch_queue_create("com.xxcc", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue1, ^{
         NSLog(@"异步 并行队列 ------%@",[NSThread currentThread]);
    });
    
    //GCD默认已经提供了全局并发队列，供整个应用使用，可以无需手动创建
    /**
     #define DISPATCH_QUEUE_PRIORITY_HIGH 2
     #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
     #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
     */
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"异步 并行队列 ------%@",[NSThread currentThread]);
    });
    
#pragma mark - 栅栏函数 （控制任务的执行顺序） 栅栏函数可以控制任务执行的顺序，栅栏函数之前的执行完毕之后，执行栅栏函数，然后在执行栅栏函数之后的
}

- (void)asyncConsurrent
{
    // 创建并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    // 并行队列 添加任务并执行
    dispatch_async(queue, ^{
         NSLog(@"异步 并行队列 ----1--%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        for (int i = 0; i<1000000; i++) {
        }
         NSLog(@"异步 并行队列 ---2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
         NSLog(@"异步 并行队列 ---3---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
         NSLog(@"异步 并行队列 ---4---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        for (int i = 0; i<10000000; i++) {
        }
        NSLog(@"异步 并行队列 ---5---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步 并行队列 ---6---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步 并行队列 ---7---%@",[NSThread currentThread]);
    });
}


- (void)downImage
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURL *url = [NSURL URLWithString:@"http://pic.58pic.com/58pic/13/87/82/27Q58PICYje_1024.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        dispatch_sync(dispatch_get_main_queue(), ^{
            _imageView.image = [UIImage imageWithData:data];
        });
    });
}


-(void)barrier
{
    //1.创建队列(并发队列)
    dispatch_queue_t queue = dispatch_queue_create("com.xxccqueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<3; i++) {
            NSLog(@"%zd-download1--%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<3; i++) {
            NSLog(@"%zd-download2--%@",i,[NSThread currentThread]);
        }
    });
    //栅栏函数
    dispatch_barrier_async(queue, ^{
        NSLog(@"我是一个栅栏函数");
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<3; i++) {
            NSLog(@"%zd-download3--%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<3; i++) {
            NSLog(@"%zd-download4--%@",i,[NSThread currentThread]);
        }
    });
}


- (void)delate
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"---%@",[NSThread currentThread]);
    });
    // 2s中之后调用run方法
    [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
    // repeats：YES 是否重复
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
}


- (void)group
{
    // 创建队列组
    dispatch_group_t group = dispatch_group_create();
    // 创建并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    // 执行队列组任务
    dispatch_group_async(group, queue, ^{
        NSLog(@"队列组 ---1---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i<10000000; i++) {
        }
        NSLog(@"队列组 ---2---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"队列组 ---3---%@",[NSThread currentThread]);
    });
    //队列组中的任务执行完毕之后，执行该函数
    dispatch_group_notify(group, queue, ^{
         NSLog(@"队列组 ---notify---%@",[NSThread currentThread]);
    });
}



/**
 假设现在系统有两个空闲资源可以被利用，但同一时间却有三个线程要进行访问，这种情况下，该如何处理呢？
 我们要下载很多图片，并发异步进行，每个下载都会开辟一个新线程，可是我们又担心太多线程肯定cpu吃不消，那么我们这里也可以用信号量控制一下最大开辟线程数。
 说白了就是可以限制线程的同事执行的个数
 */
- (void)semaphore
{
    //crate的value表示，最多几个资源可访问
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //任务1
    dispatch_async(quene, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 1");
        sleep(1);
        NSLog(@"complete task 1");
        dispatch_semaphore_signal(semaphore);
    });
    //任务2
    dispatch_async(quene, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 2");
        sleep(1);
        NSLog(@"complete task 2");
        dispatch_semaphore_signal(semaphore);
    });
    //任务3
    dispatch_async(quene, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 3");
        sleep(1);
        NSLog(@"complete task 3");
        dispatch_semaphore_signal(semaphore);
    });
}














- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end
